#include "LED.h"
#include "gpio.h"
#include "I2C_IO_Driver.h"
#include "inc/hw_memmap.h"
#include "Button.h"
#include "Buzzer.h"
#include "main.h"
#include "Relay.h"
#include "Fault.h"

enum SO_OUT {
SO_OUT_1 =0,
SO_OUT_2 =1,
SO_OUT_3 =2,
SO_OUT_4 =3,
RL_OUT_1,
RL_OUT_2,
RL_OUT_3,
RL_OUT_4
};

#define NUM_CHIPS 4
#define PORTS_PER_CHIP 2
#define NUM_PORTS (NUM_CHIPS*PORTS_PER_CHIP)

struct LedI2Cport_t {
	unsigned char I2CAddr;
	unsigned char portOffset;
	unsigned char configMask;
	unsigned char outputMask;
};
struct resource_t {
	enum LED_INDEX myResource;
	enum RATES requestorArray[LED_LAST];
	unsigned char count[RATE_END];
	unsigned char max;
	enum RATES myRate;
};
struct SO_outMask {
	enum OSO_I2C oso;
	enum SO_LED soLed;
};
struct SO_out {
	struct SO_outMask soOutMask[8];
	unsigned char lastOnMaskLed;
	unsigned char lastOffMaskLed;
	unsigned char lastOnMaskOSO;
	unsigned char lastOffMaskOSO;
};

struct LedI2Cport_t LedI2Cport [NUM_PORTS];
struct LedI2Cport_t * pLED_I2Cport[LED_LAST];
struct resource_t resourceArray[LED_GLOBAL_LAST];
struct SO_out soOut;//  = {0};

unsigned char LED_Rate[LED_LAST];
unsigned char LED_Bit[LED_LAST];
unsigned char LED_Drive[LED_LAST];
enum e_mode sysMode = MODE_NORMAL;
static unsigned char turn = 0;
static unsigned char buttonTurn = 0;

void LED_resourceArray_init(unsigned char max, enum LED_INDEX firstResource);
void LedI2Cport_assign(struct LedI2Cport_t * port, unsigned char address, unsigned char portOffset, unsigned char configMask, unsigned char outputMask);
void LED_Buzzer_setRate(enum RATES rate);

void LedI2Cport_assign(struct LedI2Cport_t * port, unsigned char address, unsigned char portOffset, unsigned char configMask, unsigned char outputMask)
{
	port->I2CAddr = address;
	port->portOffset = portOffset;
	port->configMask = configMask;
	port->outputMask = outputMask;
	sendCmdData(address,  PCA_CONFIG_PORT_0 + portOffset, configMask);
	sendCmdData(address,  PCA_OUTPUT_PORT_0 + portOffset, outputMask);
}
int LED_setRateRange(enum LED_INDEX begin, enum LED_INDEX end, enum RATES rate)
{
	if (begin > end)
		return -1;
	enum LED_INDEX i;
	for (i=begin; i<=end; i++)
	{
		LED_Rate[i] = rate;
	}
	return 0;
}
void LED_setRate(enum LED_INDEX index, enum RATES rate)
{
	LED_Rate[index] = rate;
}
void LED_resourceArray_init(unsigned char max, enum LED_INDEX firstResource)
{
	enum LED_GLOBAL_INDEX resource;
	enum LED_INDEX me = firstResource;
	enum LED_INDEX requestor;
	enum RATES rate;
	for (resource=LED_GLOBAL_BEGIN; resource<LED_GLOBAL_LAST; resource++)
	{
//		resourceArray[i].myIndex = i;
		resourceArray[resource].myResource = me++;
		resourceArray[resource].myRate = RATE_OFF;
		for (rate=RATE_BEGIN; rate<RATE_END; rate++)
		{
			resourceArray[resource].count[rate] = 0;
		}
		for (requestor=LED_Begin; requestor<LED_LAST; requestor++)
		{
			resourceArray[resource].requestorArray[requestor] = RATE_OFF;
			resourceArray[resource].count[RATE_OFF]++;
//			resourceArray[i].requestorArray[j] = RATE_OFF;
		}
		resourceArray[resource].max = resourceArray[resource].count[RATE_OFF];//resourceArray[resource].max = max;
	}
}
int LED_resourceArray_requestRate(enum LED_GLOBAL_INDEX resourceIndex, enum LED_INDEX requestorIndex, enum RATES newRate)
{
	if ((requestorIndex > LED_LAST))//||(requestorIndex < LED_Begin))
	{
		return -1; // Invalid requestor
	}
	if ((resourceIndex > LED_GLOBAL_END)||(resourceIndex < LED_GLOBAL_BEGIN))
	{
		return -2; // Invalid requestor
	}
	enum RATES lastRate = resourceArray[resourceIndex].requestorArray[requestorIndex];
	resourceArray[resourceIndex].requestorArray[requestorIndex] = newRate;
	if (resourceArray[resourceIndex].count[lastRate] != 0)
	{
		resourceArray[resourceIndex].count[lastRate]--;
	}
	if (resourceArray[resourceIndex].count[newRate] != resourceArray[resourceIndex].max)// - 1)
	{
		resourceArray[resourceIndex].count[newRate]++;
	}
	return 0;
}
int LED_resourceArray_requestRateRange(enum LED_GLOBAL_INDEX resourceIndexBegin, enum LED_GLOBAL_INDEX resourceIndexEnd, enum LED_INDEX requestorIndex, enum RATES newRate)
{
	enum LED_GLOBAL_INDEX resource;
	for (resource = resourceIndexBegin; resource <= resourceIndexEnd; resource++)
	{
		LED_resourceArray_requestRate(resource, requestorIndex, newRate);
	}
	return 0;
}
int LED_resourceArray_processLED(void)
{

	enum LED_GLOBAL_INDEX resourceIndex;
//	enum LED_INDEX requestorIndex;
	enum RATES rate;
	for (resourceIndex = LED_GLOBAL_BEGIN; resourceIndex < LED_GLOBAL_LAST; resourceIndex++)
	{
		for (rate = RATE_OFF; rate < RATE_END; rate++)
		{
			if (resourceArray[resourceIndex].count[rate] > 0)
			{
				LED_setRate(resourceArray[resourceIndex].myResource, rate);
				resourceArray[resourceIndex].myRate = rate;
			}
		}
	}
	return 0;
}
int LED_resourceArray_drive(void)
{
	return 0;
}
enum RATES LED_getRate(enum LED_INDEX index)
{
	return (enum RATES) LED_Rate[index];
}
int LED_areAnyRatesSet(enum LED_INDEX beg, enum LED_INDEX end)
{
	enum LED_INDEX i;
	for (i=beg; i<=end; i++)
	{
		if (LED_Rate[i] != RATE_OFF)
		{
			return 1;
		}
	}
	return 0;
}
void LED_test_init(void)
{
	int i;
	for (i=LED_SI_1_Alm+2; i<=LED_SI_8_Alm; i++)
	{
		LED_Rate[i] = (RATE_FAST+i)%(RATE_FAST+1);
	}
	for (i=LED_SI_1_Flt+2; i<=LED_SI_8_Flt; i++)
	{
		LED_Rate[i] = RATE_SLOW_SLOW;//(RATE_SLOW+i)%(RATE_SLOW+1);
	}
}
void LED_initBitTest(enum LED_INDEX _begin, enum LED_INDEX _end)
{
	int i;
	struct LedI2Cport_t * p = pLED_I2Cport[_begin];
	for (i=_begin; i<=_end; i++)
	{
		sendCmdData(p->I2CAddr,  PCA_OUTPUT_PORT_0 + p->portOffset, ~LED_Bit[i]);
	}
}
void LED_initI2Cport(enum LED_INDEX _begin, enum LED_INDEX _end, enum PCA_PORT_INDEX _port, enum LED_ORDER _order, unsigned char bitOffset)
{
	int i;
	for (i=_begin; i<=_end; i++)
	{
		pLED_I2Cport[i] = &LedI2Cport[_port];
		LED_Rate[i] = RATE_OFF;
		LED_Drive[i] = LED_OFF;
		if (_order == MSB)
		{
			LED_Bit[i] = 1<<(i-_begin + bitOffset);
		}
		else // (_order == LSB)
		{
			LED_Bit[i] = 0x80>>(i-_begin + bitOffset);
		}
	}
}
void LED_setBit(enum LED_INDEX led, unsigned char mask)
{
	LED_Bit[led] = mask;
}
void SO_out_init_help(enum SO_OUT me, enum OSO_I2C oso, enum SO_LED soLed)
{
	soOut.soOutMask[me].oso = oso;
	soOut.soOutMask[me].soLed = soLed;
}
unsigned char SO_out_getLastOSOon(void)
{
	return soOut.lastOnMaskOSO;
}
unsigned char SO_out_getLastLEDon(void)
{
	return soOut.lastOnMaskLed;
}
void SO_out_init(void)
{
	soOut.lastOffMaskLed = 0;
	soOut.lastOnMaskLed = 0;
	soOut.lastOffMaskOSO = 0;
	soOut.lastOnMaskOSO = 0;
	SO_out_init_help(SO_OUT_1, OSO__1, SO_1);
	SO_out_init_help(SO_OUT_2, OSO__2, SO_2);
	SO_out_init_help(SO_OUT_3, OSO__3, SO_3);
	SO_out_init_help(SO_OUT_4, OSO__4, SO_4);
}
void LED_init(void)
{
	LED_initI2Cport(LED_SI_1_Alm, LED_SI_8_Alm, PCA_U7_SI_PORT_0_INDEX,        MSB, 0);
	LED_initI2Cport(LED_SI_1_Flt, LED_SI_8_Flt, PCA_U7_SI_PORT_1_INDEX,        LSB, 0);
	LED_initI2Cport(LED_SO_1_Alm, LED_SO_8_Alm, PCA_U8_SO_PORT_0_INDEX,        MSB, 0);
	LED_initI2Cport(LED_SO_1_Flt, LED_SO_8_Flt, PCA_U8_SO_PORT_1_INDEX,        LSB, 0);
	LED_initI2Cport(LED_PANEL,    LED_GROUND,   PCA_U10_MISC_LED_PORT_1_INDEX, MSB, 1);
	LED_initI2Cport(LED_STANDBY, LED_PRIMARY, PCA_U10_MISC_LED_PORT_0_INDEX, MSB, 0);
	LED_initI2Cport(LED_ALARMS, LED_ALARMS, PCA_U10_MISC_LED_PORT_0_INDEX, MSB, 6);
	LED_setBit(LED_ALARMS, ALARMS); // override bit mask setting

	//	for (i=0; i<=NUM_PORTS;)
	{
		LedI2Cport_assign(&LedI2Cport[0], PCA_U7_SI+0, 0, PCA_CONFIG_SET_ALL_TO_OUTPUT, LED_PORT_ALL_OFF);
		LedI2Cport_assign(&LedI2Cport[1], PCA_U7_SI+0, 1, PCA_CONFIG_SET_ALL_TO_OUTPUT, LED_PORT_ALL_OFF);
		LedI2Cport_assign(&LedI2Cport[2], PCA_U7_SI+1, 0, PCA_CONFIG_SET_ALL_TO_OUTPUT, LED_PORT_ALL_OFF);  // U8
		LedI2Cport_assign(&LedI2Cport[3], PCA_U7_SI+1, 1, PCA_CONFIG_SET_ALL_TO_OUTPUT, LED_PORT_ALL_OFF);
		LedI2Cport_assign(&LedI2Cport[4], PCA_U7_SI+2, 0, PCA_CONFIG_U10_P0,            LED_PORT_ALL_OFF);  // U10
		LedI2Cport_assign(&LedI2Cport[5], PCA_U7_SI+2, 1, PCA_CONFIG_U10_P1,            LED_PORT_ALL_OFF);
		LedI2Cport_assign(&LedI2Cport[6], PCA_U7_SI+3, 0, PCA_CONFIG_SET_ALL_TO_INTPUT, LED_PORT_ALL_OFF);  // U9
		LedI2Cport_assign(&LedI2Cport[7], PCA_U7_SI+3, 1, PCA_CONFIG_SET_ALL_TO_OUTPUT, LED_PORT_ALL_OFF);
//		i+=2;
	}
	struct LedI2Cport_t * p = pLED_I2Cport[LED_SI_1_Alm];
	p = &LedI2Cport[0];//pLED_I2Cport[0];
	while (p != &LedI2Cport[NUM_PORTS-2]) // turn off all led's
	{
//		sendCmdData(p->I2CAddr,  PCA_CONFIG_PORT_0 + p->portOffset, p->outputMask);
		sendCmdData(p->I2CAddr,  PCA_OUTPUT_PORT_0 + p->portOffset, p->outputMask);
		p++;
	}
	LED_resourceArray_init(LED_LAST, LED_PANEL);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_1_Alm, RATE_OFF);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_1_Alm, RATE_FAST);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_2_Alm, RATE_FAST);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_2_Alm, RATE_ON);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_2_Alm, RATE_SLOW);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_2_Alm, RATE_OFF);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_1_Alm, RATE_FAST);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_1_Alm, RATE_ON);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_1_Alm, RATE_SLOW);
	LED_resourceArray_requestRate(LED_GLOBAL_TROUBLE, LED_SI_1_Alm, RATE_OFF);

	LED_Buzzer_setRate(RATE_OFF);
}
enum RATES buzzRate = RATE_OFF;
void LED_Buzzer_setRate(enum RATES rate)
{
	buzzRate = rate;
}
enum RATES LED_Buzzer_getRate(void)
{
	return buzzRate;
}
void LED_thread_BuzzerHelper(enum RATES rate)
{
	static unsigned int buzzTimer = 0;
	static unsigned char stateAllAcked = 0;
	static unsigned int lastTurn = 0;
	if (lastTurn == buttonTurn) {
		__no_operation();
		return;		// rev -- it wasn't necessisary to update the Led's every time
	}
	if ((buttonTurn - lastTurn)>1)
	{
		__no_operation();
	}
	lastTurn = buttonTurn;
	switch (rate)
	{
		case RATE_FAST:
			if (buttonTurn%2<1)
			{
				Buzzer_on();
			}
			else
			{
				Buzzer_off();
			}
			break;
		case RATE_SLOW:
			if (buttonTurn%4<2)
			{
				Buzzer_on();
			}
			else
			{
				Buzzer_off();
			}
			break;
		case RATE_SLOW_SLOW:
			if (buttonTurn%20<10)
			{
				Buzzer_on();
			}
			else
			{
				Buzzer_off();
			}
		break;
		case RATE_ON:
			switch (stateAllAcked)
			{
				case 0: // count down
					Buzzer_off();
					if (buzzTimer++ >= (45*4))
					{
						buzzTimer = 0;
						stateAllAcked = 1;
						Buzzer_on();
					}
				break;
				case 1: //
					stateAllAcked = 2;
					Buzzer_off();
				break;
				case 2:
					stateAllAcked = 0;
					Buzzer_on();
				break;
			}

			break;
		case RATE_OFF:
		default:
			Buzzer_off();
			break;
	}
}
void LED_buzzerLogic(void)
{
	enum LED_INDEX i;
	enum RATES buzzRate = RATE_OFF;

	for (i=LED_SI_1_Alm; i<=LED_end; i++) // new
//	for (i=LED_SI_1_Alm; i<=LED_SI_8_Flt; i++)
	{
//		if (LED_getRate(i) > RATE_ON)
		if (LED_getRate(i) > RATE_OFF) // new
		{
			if (pConfigMemRAM->si[i].fxn != SI_Fxn_SILENT_STATUS_CHANGE)
			{
				if (LED_getRate(i) == RATE_FAST)
				{
					buzzRate = RATE_FAST;
					break;
				}
				else if (LED_getRate(i) == RATE_SLOW)
				{
					buzzRate = RATE_SLOW;
				}
				else if (LED_getRate(i) == RATE_SLOW_SLOW)
				{
					if (buzzRate <= RATE_SLOW_SLOW)
					{
						buzzRate = RATE_SLOW_SLOW;
					}
				}
				else if (LED_getRate(i) == RATE_ON)
				{
					if (buzzRate <= RATE_ON)
					{
						buzzRate = RATE_ON;
					}
				}
			}
		}
	}
//	buzzRate = RATE_FAST;
	if (sysMode == MODE_SERVICE)
	{
		LED_Buzzer_setRate(RATE_ON);
	}
	else
	{
		LED_Buzzer_setRate(buzzRate);
	}
//	LED_thread_BuzzerHelper(LED_Buzzer_getRate());
}
void LED_thread_helper(unsigned int index, unsigned char * mask)
{
//	Buttons_check();
	unsigned char rate    = LED_Rate[index];
//	unsigned char mask;
//	unsigned char I2CAddr = LED_I2CAddr[index];
//	unsigned char port    = LED_I2CPort[index];
//	unsigned char I2CAddr = LED_I2CConfig[index];
//	unsigned char I2CAddr = LED_I2COutputs[index];

	switch (rate)
	{
		case RATE_FAST:
			if (turn%2<1)
			{
				*mask &= ~LED_Bit[index];
//				sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, ~PANEL);
//				Buzzer_on();
			}
			else
			{
				*mask |= LED_Bit[index];
//				sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, 0xFF);
//				Buzzer_off();
			}
			break;
		case RATE_SLOW:
			if (turn%4<2)
			{
				*mask &= ~LED_Bit[index];
//				sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, ~PANEL);
//				Buzzer_on();
			}
			else
			{
				*mask |= LED_Bit[index];
//				sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, 0xFF);
//				Buzzer_off();
			}
			break;
		case RATE_SLOW_SLOW:
			if (turn%20<10)
			{
				*mask &= ~LED_Bit[index];
//				sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, ~PANEL);
//				Buzzer_on();
			}
			else
			{
				*mask |= LED_Bit[index];
//				sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, 0xFF);
//				Buzzer_off();
			}
		break;
		case RATE_ON:
			*mask &= ~LED_Bit[index];
//			sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, ~PANEL);
			break;
		case RATE_OFF:
		default:
			*mask |= LED_Bit[index];
//			sendCmdData(PCA_U10_MISC_LED,  PCA_OUTPUT_PORT_1, 0xFF);
			break;
	}
}
void LED_setMode(enum e_mode _mode)
{
	if (sysMode != MODE_NORMAL)
	{
		__no_operation();
	}
	sysMode = _mode;
	Fault_setMode(_mode);
}
void REL_marshalLEDtoRelay(enum LED_INDEX _begin, enum LED_INDEX _end)
{
	unsigned int i;
//	struct LedI2Cport_t * p;// = LED_I2Cport[LED_SI_1_Alm];
//	unsigned char onMaskLed=0, offMaskLed=0;
//	unsigned char onMaskOSO=0, offMaskOSO=0;
//	unsigned char me = 0;
	enum Relays myRelay = (enum Relays)0;
//	p = pLED_I2Cport[_begin];
//	mask = p->outputMask;
	for (i=_begin; i<=_end; i++)
	{
//		me = (unsigned char)(i - _begin + RL_OUT_1);
		myRelay = (enum Relays)(i - _begin);
		myRelay += Relay_1;
		if (LED_Rate[i] == RATE_ON)
		{
			if ((sysMode == MODE_SERVICE) &&
					(pConfigMemRAM->rl[i - _begin].InhibitService == SO_configByte_InhibitService_isOff))
			{
				if (pConfigMemRAM->rl[i - _begin].NormallyOn == SO_configByte_NormallyOn_isOff)
				{
					REL_resourceArray_requestRelay(myRelay, (enum LED_INDEX)i, Relay_Off);
				}
				else
				{
					REL_resourceArray_requestRelay(myRelay, (enum LED_INDEX)i, Relay_On);
				}
//				onMaskLed |= soOut.soOutMask[me].soLed;
			}
			else
			{
				if (pConfigMemRAM->rl[i - _begin].NormallyOn == SO_configByte_NormallyOn_isOff)
				{
					REL_resourceArray_requestRelay(myRelay, (enum LED_INDEX)i, Relay_On);
				}
				else
				{
					REL_resourceArray_requestRelay(myRelay, (enum LED_INDEX)i, Relay_Off);
				}
//				onMaskLed |= soOut.soOutMask[me].soLed;
//				onMaskOSO |= soOut.soOutMask[me].oso;
			}
		}
		else
		{
			if (pConfigMemRAM->rl[i - _begin].NormallyOn == SO_configByte_NormallyOn_isOff)
			{
				REL_resourceArray_requestRelay(myRelay, (enum LED_INDEX)i, Relay_Off);
			}
			else
			{
				REL_resourceArray_requestRelay(myRelay, (enum LED_INDEX)i, Relay_On);
			}
//			offMaskLed |= soOut.soOutMask[me].soLed;
//			offMaskOSO |= soOut.soOutMask[me].oso;
		}
	}
//		LED_thread_helper(i, &mask);

/*	if ((soOut.lastOnMaskOSO != onMaskOSO)&&(onMaskOSO))
	{
//		I2C_SO_On(onMaskOSO, onMaskLed);
		REL_resourceArray_requestRelay(Relay_1 + me, (enum LED_INDEX)i, Relay_On);
		soOut.lastOnMaskLed = onMaskLed;
		soOut.lastOnMaskOSO = onMaskOSO;
	}
	if (offMaskLed)
	{
//		I2C_SO_Off(offMaskOSO, offMaskLed);
		REL_resourceArray_requestRelay(Relay_1 + me, (enum LED_INDEX)i, Relay_Off);
		soOut.lastOffMaskLed = offMaskLed;
		soOut.lastOffMaskOSO = offMaskOSO;
	}*/
}
unsigned char tickSendMsg = 0;
unsigned char  numSObytes = 0;
void LED_updateTickSendMsg(unsigned char bytes)
{
	tickSendMsg = 1;
	numSObytes = bytes;
}
unsigned char soLed_msg [10];
BYTE I2C_SO_status = 0;
void I2C_SO_setStatus(BYTE status)
{
	I2C_SO_status = status;
}
BYTE I2C_SO_getStatus(void)
{
	return I2C_SO_status;
}
void LED_marshalLEDperI2CportSO(enum LED_INDEX _begin, enum LED_INDEX _end)
{
	unsigned int i;
//	struct LedI2Cport_t * p;// = LED_I2Cport[LED_SI_1_Alm];
	unsigned char onMaskLed=0, offMaskLed=0;
	unsigned char onMaskOSO=0, offMaskOSO=0;
	unsigned char onMaskState=0;
	unsigned char me = 0;
//	p = pLED_I2Cport[_begin];
//	mask = p->outputMask;
	for (i=_begin; i<=_end; i++)
	{
		me = (unsigned char)(i - _begin);
		if (LED_Rate[i] == RATE_ON)
		{
//			onMask |= LED_Bit[i];
#if 1
			if ((sysMode == MODE_SERVICE) &&
					(pConfigMemRAM->so[me].InhibitService == SO_configByte_InhibitService_isOff))
			{
				onMaskLed |= soOut.soOutMask[me].soLed;
				if (pConfigMemRAM->so[me].NormallyOn == SO_configByte_NormallyOn_isOn)
				{
					onMaskOSO |= soOut.soOutMask[me].oso;
				}
				else
				{
					offMaskOSO |= soOut.soOutMask[me].oso;
				}
			}
			else
#endif
			{
				onMaskLed |= soOut.soOutMask[me].soLed;
				if (pConfigMemRAM->so[me].NormallyOn == SO_configByte_NormallyOn_isOff)
				{
					onMaskOSO |= soOut.soOutMask[me].oso;
					onMaskState |= soOut.soOutMask[me].oso;
				}
				else
				{
					offMaskOSO |= soOut.soOutMask[me].oso;
				}
			}
		}
		else
		{
			offMaskLed |= soOut.soOutMask[me].soLed;
			if (pConfigMemRAM->so[me].NormallyOn == SO_configByte_NormallyOn_isOff)
			{
				offMaskOSO |= soOut.soOutMask[me].oso;
			}
			else
			{
				onMaskOSO |= soOut.soOutMask[me].oso;
				onMaskState |= soOut.soOutMask[me].oso;
			}
		}
//		LED_thread_helper(i, &mask);
	}
	I2C_SO_setStatus(onMaskState);
	if ((soOut.lastOnMaskOSO != onMaskOSO)&&(onMaskOSO))
	{
		I2C_SO_On(onMaskOSO, onMaskLed);
	}
//	if (offMaskLed)
	if ((soOut.lastOffMaskOSO != offMaskOSO)&&(offMaskOSO))
	{
		I2C_SO_Off(offMaskOSO, offMaskLed);
	}
	soOut.lastOnMaskLed = onMaskLed;
	soOut.lastOnMaskOSO = onMaskOSO;
	soOut.lastOffMaskLed = offMaskLed;
	soOut.lastOffMaskOSO = offMaskOSO;
#if DEBUG_SERIAL_SO
	if (tickSendMsg)
	{
		tickSendMsg = 0;
		unsigned char byte = 0;

		soLed_msg[byte++] = sysMode;
		soLed_msg[byte++] = onMaskLed;
		soLed_msg[byte++] = onMaskOSO;
		soLed_msg[byte++] = offMaskLed;
		soLed_msg[byte++] = offMaskOSO;
		soLed_msg[byte++] = LED_Rate[_begin];
		soLed_msg[byte++] = pConfigMemRAM->so[0].InhibitService;

		Test_Serial_msgAppend(soLed_msg, byte, numSObytes);
		Test_Serial_sendMsg(DebugCmd_SO_1,  numSObytes+byte);
	}
#endif

//	sendCmdData(p->I2CAddr,  PCA_OUTPUT_PORT_0 + p->portOffset, mask);
//	p->outputMask = mask;
}
void LED_test_marshalLEDperI2CportSOREL(void)
{
	LED_marshalLEDperI2CportSO(LED_SO_1_Alm, LED_SO_4_Alm);
	REL_marshalLEDtoRelay(LED_SO_5_Alm, LED_SO_8_Alm);
}
void LED_marshalLEDperI2Cport(enum LED_INDEX _begin, enum LED_INDEX _end, unsigned int turn)
{
	unsigned int i;
	struct LedI2Cport_t * p;// = LED_I2Cport[LED_SI_1_Alm];
	unsigned char mask;// = p->outputMask;
	p = pLED_I2Cport[_begin];
	mask = p->outputMask;
//	if (turn%3==0) // update mask, slow down processing
	{
		for (i=_begin; i<=_end; i++)
		{
			LED_thread_helper(i, &mask);
	//		p = LED_I2Cport[i];
	//		if (LED_Rate[i]==RATES_FAST)
	//		mask_fas |= LED_Drive[i]&(i-LED_SI_1_Alm);
		}
		if (mask != p->outputMask)
		{
			sendCmdData(p->I2CAddr,  PCA_OUTPUT_PORT_0 + p->portOffset, mask);
			__no_operation();
		}
	}
	p->outputMask = mask;
}
void LED_thread(void)
{
	static unsigned int lastTurn = 0;

	if (lastTurn == turn) return;		// rev -- it wasn't necessisary to update the Led's every time
	test_testPin3_On();
	lastTurn = turn;					// rev -- to it is synched to proper refresh rate
//	LED_setRate(LED_ALARMS , RATE_FAST);
	LED_marshalLEDperI2Cport(LED_SI_1_Alm, LED_SI_8_Alm, turn);
	LED_marshalLEDperI2Cport(LED_SI_1_Flt, LED_SI_8_Flt, turn);
//	LED_marshalLEDperI2Cport(LED_SO_1_Alm, LED_SO_8_Alm);
//	LED_marshalLEDperI2Cport(LED_SO_5_Alm, LED_SO_8_Alm);
	LED_marshalLEDperI2Cport(LED_SO_1_Flt, LED_SO_8_Flt, turn);
	LED_marshalLEDperI2Cport(LED_PANEL, LED_GROUND, turn);
	LED_marshalLEDperI2Cport(LED_STANDBY, LED_ALARMS, turn);
//	LED_setRate(LED_SO_1_Alm, RATE_ON);
//	LED_setRate(LED_SO_3_Alm, RATE_ON);
//	LED_marshalLEDperI2CportSO(LED_SO_1_Alm, LED_SO_4_Alm);
//	LED_setRate(LED_SO_1_Alm, RATE_OFF);
//	LED_setRate(LED_SO_3_Alm, RATE_OFF);
	if (sysMode != MODE_LAMP_TEST)
	{
		LED_marshalLEDperI2CportSO(LED_SO_1_Alm, LED_SO_4_Alm);
		REL_marshalLEDtoRelay(LED_SO_5_Alm, LED_SO_8_Alm);
		LED_marshalLEDperI2Cport(LED_SO_1_Alm, LED_SO_8_Alm, turn);
	}
	else
	{
		LED_marshalLEDperI2Cport(LED_SO_1_Alm, LED_SO_8_Alm, turn);
//		LED_marshalLEDperI2Cport(LED_SO_5_Alm, LED_SO_8_Alm, turn);
	}
	LED_buzzerLogic();
	test_testPin3_Off();
}
void LED_buttonUpdateTimer(void)
{
	buttonTurn++;
}
void LED_updateTimer(void)
{
	turn++;
	LED_buttonUpdateTimer();
}
enum LED_GLOBAL_INDEX globalLedToIndex(enum LED_INDEX led)
{
	enum LED_GLOBAL_INDEX index;
	if (led == LED_noGlobalAlmLed)
	{
		index = LED_GLOBAL_INVALID;
	}
	else
	{
		unsigned char temp = led - LED_PANEL;
		index = (enum LED_GLOBAL_INDEX)temp;
	}
	return index;
}
